/* -*- C++ -*- */

//=============================================================================
/*
* @author Feloweria <380374483@qq.com>
* Copyright (C) Feloweria
*
* $ID 2014-05-14 11:25:19 AM
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*
* @version 1.0
*/
//=============================================================================


#include "Network/SocketThread.h"
#include "Network/Socket.h"

#ifdef __LINUX__
	#include <sys/epoll.h>
#endif

FELOWRIA_BEGIN

int32 SocketThread::max_size = 10000;

SocketThread::SocketThread()
:
#ifdef __LINUX__
fd(epoll_create(max_size)),
#endif

#ifdef __WINDOWS__
completion_port(CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, (ULONG_PTR)0, 0)),
#endif
size(0)
{

}

SocketThread::~SocketThread()
{

}

bool SocketThread::Register(Socket *socket)
{
	if(!socket)
		return false;
	++size;

#ifdef __LINUX__
	epoll_event event;
	event.events = EPOLLIN | EPOLLOUT | EPOLLET;
	event.data.ptr = socket;

	return !epoll_ctl(fd, EPOLL_CTL_ADD, socket->Handle(), &event);
#endif
	
#ifdef __WINDOWS__
	return CreateIoCompletionPort((HANDLE)socket->Handle(), completion_port, (ULONG_PTR)socket, 0) != 0;
#endif
}

bool SocketThread::UnRegister(Socket *socket)
{
#ifdef __LINUX__
	--size;
	return !epoll_ctl(fd, EPOLL_CTL_DEL, socket->Handle() ,NULL);
#endif

#ifdef __WINDOWS__
	return true;
#endif
}

bool SocketThread::Excute()
{
#ifdef __LINUX__
    epoll_event event;

	int size = epoll_wait(fd,&event,1,-1);
	
	if(-1 == size)
	    return true;
	
	Socket *socket = (Socket*)event.data.ptr;

	if(event.events & EPOLLIN)
		socket->Read();

	 if(event.events & EPOLLOUT)
		socket->Send();
			
	if((event.events & EPOLLRDHUP) || (event.events & EPOLLERR))
		socket->Disconnect();
#endif

#ifdef __WINDOWS__
	OVERLAPPEDEVENT *io_event;
	Socket *socket = NULL;
	DWORD len = 0;
	
	if (!GetQueuedCompletionStatus(completion_port, &len, (PULONG_PTR)&socket, (OVERLAPPED**)&io_event, INFINITE))
		return true;

	if (len == 0)
	{
		socket->Disconnect();
		return true;
	}

	if (io_event->type == SOCKET_EVENT_READ)
	{
		io_event->socket_buffer->WriteSkip(len);
		socket->Read();
	}

	if (io_event->type == SOCKET_EVENT_WRITE)
	{
		io_event->socket_buffer->ReadSkip(len);
		socket->Send();
	}
#endif

	return true;
}

FELOWRIA_END
